﻿using Agility.Testing.Silverlight.AppDriver;
using Agility.ViewModels;
using Microsoft.Silverlight.Testing;
using NUnit.Framework;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace Agility.Testing.Silverlight.ViewModels
{
    [TestFixture]
    public class RegistrationFormViewModelTests : SilverlightTest
    {
        RegistrationFormViewModel target;

        #region optional setup and tear down methods
        //// Called before the first test to setup the whole fixture
        //[TestFixtureSetUp]
        //public void TestFixtureSetup()
        //{
        //}

        //// Called after the last test to tear down the whole fixture
        //[TestFixtureTearDown]
        //public void TestFixtureTearDown()
        //{
        //}

        //// Called before each test
        [SetUp]
        public void TestSetup()
        {
            this.target = new RegistrationFormViewModel(WebContext.Current.Authentication);
        }

        //// Called after each test
        //[TearDown]
        //public void TestTearDown()
        //{ 
        //}

        #endregion

        #region UnitTests
        [Test]
        [Category("UnitTest")]
        public void TestPassword()
        {
            // Arrange
            string expected = "This is the password.";
            string actual;

            // Act
            this.target.PasswordAccessor = () => expected;
            actual = target.Password;

            // Assert
            Assert.AreEqual(expected, actual);
        }

        [Test]
        [Category("UnitTest")]
        public void TestPasswordConfirmation()
        {
            // Arrange
            string expected = "This is the password.";
            string actual;

            // Act
            this.target.PasswordConfirmationAccessor = () => expected;
            actual = target.PasswordConfirmation;

            // Assert
            Assert.AreEqual(expected, actual);
        }

        [Test]
        [Category("UnitTest")]
        [TestCase("Password", TestName = "Password")]
        [TestCase("PasswordConfirmation", TestName = "PasswordConfirmation")]
        public void TestRequiredAttribute(string propertyName)
        {
            // Arrange
            PropertyInfo target = typeof(RegistrationFormViewModel).GetProperty(propertyName);
            RequiredAttribute actual = target.GetCustomAttributes(typeof(RequiredAttribute), false)
                                        .Cast<RequiredAttribute>()
                                        .FirstOrDefault();
            string message = string.Format(CultureInfo.InvariantCulture, "RequiredAttribute is missing on RegistrationData.{0}", propertyName);

            // Assert
            Assert.NotNull(actual, message);
        }

        [Test]
        [Category("UnitTest")]
        public void TestStringLengthAttribute()
        {
            // Arrange
            PropertyInfo target = typeof(RegistrationFormViewModel).GetProperty("Password");
            StringLengthAttribute actual = target.GetCustomAttributes(typeof(StringLengthAttribute), false)
                                                    .Cast<StringLengthAttribute>()
                                                    .FirstOrDefault();
            string isMissingMessage = "StringLengthAttribute is missing on RegistrationData.Password";
            string minimumLengthMessage = "MinimumLengthAttribute is not set correctly on RegistrationData.Password";
            string maximumLengthMessage = "MaximumLengthAttribute is not set correctly on RegistrationData.Password";

            // Assert
            Assert.NotNull(actual, isMissingMessage);
            Assert.AreEqual(8, actual.MinimumLength, minimumLengthMessage);
            Assert.AreEqual(50, actual.MaximumLength, maximumLengthMessage);
        }

        [Test]
        [Category("UnitTest")]
        public void TestRegularExpressionAttribute()
        {
            // Arrange
            PropertyInfo target = typeof(RegistrationFormViewModel).GetProperty("Password");
            string expected = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.*[\W]).*$";
            RegularExpressionAttribute actual = target.GetCustomAttributes(typeof(RegularExpressionAttribute), false)
                                                    .Cast<RegularExpressionAttribute>()
                                                    .FirstOrDefault();
            string isMissingMessage = "RegularExpressionAttribute is missing on RegistrationData.Password";
            string patternMatchMessage = "RegularExpression pattern does not match for RegistrationData.Password";

            // Assert
            Assert.NotNull(actual, isMissingMessage);
            Assert.AreEqual(expected, actual.Pattern, patternMatchMessage);
        }

        [Test]
        [Category("UnitTest")]
        [Asynchronous]
        public void TestRegisterUserSuccess()
        {
            RegistrationResult expectedResult = RegistrationResult.IsExpectedDialogResult |
                                                RegistrationResult.LoggedIn;
            AdministrationDriver adminDriver = new AdministrationDriver(TestType.UnitTest);
            EnqueueCallback(() => adminDriver.RegisterUser("TestUser"));
            EnqueueConditional(() => adminDriver.RegistrationCompleted == true);
            EnqueueCallback(() => Assert.AreEqual(expectedResult, adminDriver.ConfirmRegistrationResult()));
            EnqueueTestComplete();
        }

        [Test]
        [Category("UnitTest")]
        [Asynchronous]
        public void TestRegisterUserDuplicateUserName()
        {
            RegistrationResult expectedResult = RegistrationResult.IsExpectedDialogResult |
                                                RegistrationResult.IsExpectedErrorMessage |
                                                RegistrationResult.HasValidationErrors;
            AdministrationDriver adminDriver = new AdministrationDriver(TestType.UnitTest);
            EnqueueCallback(() => adminDriver.RegisterUser("Test User", false, true, false));
            EnqueueConditional(() => adminDriver.RegistrationCompleted == true);
            EnqueueCallback(() => Assert.AreEqual(expectedResult, adminDriver.ConfirmRegistrationResult()));
            EnqueueTestComplete();
        }

        [Test]
        [Category("UnitTest")]
        [Asynchronous]
        public void TestRegisterUserDuplicateEmail()
        {
            RegistrationResult expectedResult = RegistrationResult.IsExpectedDialogResult | 
                                                RegistrationResult.IsExpectedErrorMessage | 
                                                RegistrationResult.HasValidationErrors;
            AdministrationDriver adminDriver = new AdministrationDriver(TestType.UnitTest);
            EnqueueCallback(() => adminDriver.RegisterUser("Test User", true, false, false));
            EnqueueConditional(() => adminDriver.RegistrationCompleted == true);
            EnqueueCallback(() => Assert.AreEqual(expectedResult, adminDriver.ConfirmRegistrationResult()));
            EnqueueTestComplete();
        }

        [Test]
        [Category("UnitTest")]
        [Asynchronous]
        public void TestRegisterUserFailure()
        {
            RegistrationResult expectedResult = RegistrationResult.IsExpectedDialogResult |
                                                RegistrationResult.IsExpectedErrorMessage;
            AdministrationDriver adminDriver = new AdministrationDriver(TestType.UnitTest);
            EnqueueCallback(() => adminDriver.RegisterUser("Test User", false, false, true));
            EnqueueConditional(() => adminDriver.RegistrationCompleted == true);
            EnqueueCallback(() => Assert.AreEqual(expectedResult, adminDriver.ConfirmRegistrationResult()));
            EnqueueTestComplete();
        }

        #endregion

    }
}
